package com.example.bbs.job;

import com.example.bbs.domain.entity.Post;
import com.example.bbs.kafka.producer.PostProducer;
import com.example.bbs.service.PostService;
import com.example.bbs.util.RedisKeyUtil;
import com.example.bbs.util.ThreadPoolUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class PostHotScoreRefreshJob {

    @Resource
    private RedisTemplate commonRedisTemplate;

    @Autowired
    private PostService postService;

    @Resource
    private RedisTemplate postInfoRedisTemplate;

    @Autowired
    private PostProducer postProducer;

    private final static String HOT_RANK_INIT_TIME = "2022-01-01 00:00:00";

    @PostConstruct
    public void exectue() {
        /**
         * 定时刷新帖子分数, 统计热度排行
         *
         */
        ThreadPoolUtil.scheduledThreadPool.scheduleWithFixedDelay(() -> {
            BoundSetOperations boundSetOperations = commonRedisTemplate.boundSetOps(RedisKeyUtil.CHANGED_POST_SET_KEY);
            if (boundSetOperations.size() == 0) return;
            while (boundSetOperations.size() > 0) {
                String postId = (String) boundSetOperations.pop();
                //刷新帖子分数, 统计热度排行
                refreshScoreAndRank(postId);
            }
            log.info("帖子分数刷新完毕.....");

        }, 0, 70, TimeUnit.SECONDS);

        /**
         * 定时合并天，周排行榜
         *
         */
        ThreadPoolUtil.scheduledThreadPool.scheduleWithFixedDelay(() -> {
            //合并一天
            refreshDay();
            //合并一周
            refreshWeek();
        }, 0, 60, TimeUnit.SECONDS);
    }




    /**
     * 刷新帖子分数, 并同步数据，统计热度排行
     *
     * @return
     */
    private void refreshScoreAndRank(String postId) {
        //拿到帖子数据
        Post post = postService.getPostByPostId(postId);

        //分数计算字段数据
        Integer type = post.getType();
        Date createTime = post.getCreateTime();
        Integer likeCount = post.getLikeCount();
        Integer viewCount = post.getViewCount();
        Integer commentCount = post.getCommentCount();

        //计算初始时间
        DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date initTIme = null;
        try {
            initTIme = df.parse(HOT_RANK_INIT_TIME);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        long diff = createTime.getTime() - initTIme.getTime();//这样得到的差值是毫秒级别
        long days = diff / (1000 * 60 * 60 * 24); //获取天数差值

        //计算新的分数
        Double score = Math.log10(type * 60 + likeCount * 4 + viewCount * 2 + commentCount * 8) +
                Math.log10(days);
        if (score < 0) score = 0.0;

        //同步到redis帖子数据
        postInfoRedisTemplate.opsForHash().put(postId, "score", score);
        post.setScore(score);

        //发送帖子更新消息
        postProducer.send("post-update", post);
        //计算当前小时key
        long currentTimeKey = System.currentTimeMillis() / (1000 * 60 * 60);
        String hotPostListHourKey = RedisKeyUtil.getHotPostListHourKey(currentTimeKey);
        //存入zset集合中，统计热度排行
        commonRedisTemplate.opsForZSet().add(hotPostListHourKey, postId, score);

    }



    private void refreshDay() {
        //获取当前小时key
        long currentTimeKey = System.currentTimeMillis() / (1000 * 60 * 60);
        String hotPostListHourKey = RedisKeyUtil.getHotPostListHourKey(currentTimeKey);
        List<String> otherKeys = new ArrayList<>();
        //拿到前面23个小时的key
        for (int i = 1; i < 23; i++) {
            String key = RedisKeyUtil.getHotPostListHourKey(currentTimeKey - i);
            otherKeys.add(key);
        }
        //把当前的时间key往后退23小时, 求出并集存入天排行榜中
        commonRedisTemplate.opsForZSet().unionAndStore(hotPostListHourKey, otherKeys, RedisKeyUtil.HOT_POST_RANK_DAY_KEY);
        //设置当天的key40天过期
        for (int i = 1; i < 24; i++) {
            String key = RedisKeyUtil.getHotPostListHourKey(currentTimeKey - i);
            commonRedisTemplate.expire(key, 40, TimeUnit.DAYS);
        }
        log.info("今日最热排行刷新完毕.......");
    }

    private void refreshWeek() {
        //获取当前小时key
        long currentTimeKey = System.currentTimeMillis() / (1000 * 60 * 60);
        String hotPostListHourKey = RedisKeyUtil.getHotPostListHourKey(currentTimeKey);
        List<String> otherKeys = new ArrayList<>();
        //拿到前面23个小时的key
        for (int i = 1; i < 24 * 7 - 1; i++) {
            String key = RedisKeyUtil.getHotPostListHourKey(currentTimeKey - i);
            otherKeys.add(key);
        }
        //把当前的时间key往后退24*7小时, 求出并集存入周排行榜中
        commonRedisTemplate.opsForZSet().unionAndStore(hotPostListHourKey, otherKeys, RedisKeyUtil.HOT_POST_RANK_WEEK_KEY);
        log.info("本周最热排行刷新完毕.......");
    }
}
